package com.acc.sys.framework;


import apijson.*;
import apijson.framework.APIJSONConstant;
import apijson.framework.APIJSONCreator;
import apijson.framework.APIJSONFunctionParser;
import apijson.orm.JSONRequest;
import apijson.orm.script.JavaScriptExecutor;
import apijson.orm.script.ScriptExecutor;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import lombok.extern.slf4j.Slf4j;

import java.rmi.ServerException;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.Map;

import static apijson.RequestMethod.GET;
import static apijson.framework.APIJSONConstant.FUNCTION_;
import static apijson.framework.APIJSONConstant.SCRIPT_;

@Slf4j
public class AccFunctionParser extends APIJSONFunctionParser<Long> {


    /**
     * 初始化，加载所有远程函数配置，并校验是否已在应用层代码实现
     *
     * @param shutdownWhenServerError
     * @param creator
     * @param table                   表内自定义数据过滤条件
     * @return
     * @throws ServerException
     */
    @SuppressWarnings("unchecked")
    public static <T extends Object> JSONObject init(boolean shutdownWhenServerError, APIJSONCreator<T> creator, JSONObject table) throws ServerException {
        if (creator == null) {
            creator = (APIJSONCreator<T>) APIJSON_CREATOR;
        }
        APIJSON_CREATOR = creator;
        boolean isAll = table == null || table.isEmpty();
        JSONObject request = new JSONObject();

        // 可以用它，因为 Function 表必须存在，没有绕过校验的配置 // 不能用这个来优化，因为可能配置了不校验远程函数是否存在
        {   // [] <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
            JSONRequest item = new JSONRequest();

            {   // Function <<<<<<<<<<<<<<<<<<<<<<<<<<<<<
                JSONObject function = isAll ? new JSONRequest() : table;
                if (!Log.DEBUG) {
                    function.put(APIJSONConstant.KEY_DEBUG, 0);
                }
                item.put(FUNCTION_, function);
            }   // Function >>>>>>>>>>>>>>>>>>>>>>>>>>>>>

            if (ENABLE_SCRIPT_FUNCTION) { // Script <<<<<<<<<<<<<<<<<<<<<<<<<<<<<
                JSONRequest script = new JSONRequest();
                script.put("name@", "/Function/name");
                script.put("simple", 0);
                item.put(SCRIPT_, script);
            }   // Script >>>>>>>>>>>>>>>>>>>>>>>>>>>>>

            request.putAll(item.toArray(0, 0));
        }   // [] >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>


        JSONObject response = creator.createParser().setMethod(GET).setNeedVerify(false).parseResponse(request);
        if (!JSONResponse.isSuccess(response)) {
            onServerError("\n\n\n\n\n !!!! 查询远程函数异常 !!!\n" + response.getString(JSONResponse.KEY_MSG) + "\n\n\n\n\n", shutdownWhenServerError);
        }

        //初始化默认脚本引擎,避免增量
        if (isAll || SCRIPT_EXECUTOR_MAP.get("js") == null) {
            ScriptExecutor javaScriptExecutor = new JavaScriptExecutor();
            javaScriptExecutor.init();
            SCRIPT_EXECUTOR_MAP.put("js", javaScriptExecutor);
            SCRIPT_EXECUTOR_MAP.put("JavaScript", javaScriptExecutor);
            SCRIPT_EXECUTOR_MAP.put("javascript", javaScriptExecutor);
        }
        Map<String, JSONObject> scriptMap = new HashMap<>();
        JSONArray scriptList = response.getJSONArray("[]"); // response.getJSONArray(SCRIPT_ + "[]");
        if (scriptList != null && !scriptList.isEmpty()) {
            Map<String, JSONObject> newMap = new LinkedHashMap<>();
            for (int i = 0; i < scriptList.size(); i++) {
                JSONObject item = scriptList.getJSONObject(i);
                item = item == null ? null : item.getJSONObject(SCRIPT_);
                if (item == null) { // 关联查不到很正常
                    continue;
                }

                String n = item.getString("name");
                if (!StringUtil.isName(n)) {
                    onServerError("Script 表字段 name 的值 " + n + " 不合法！必须为合法的方法名字符串！", shutdownWhenServerError);
                }

                String s = item.getString("script");
                if (StringUtil.isEmpty(s, true)) {
                    onServerError("Script 表字段 script 的值 " + s + " 不合法！不能为空！", shutdownWhenServerError);
                }
                newMap.put(n, item);
            }

            scriptMap = newMap;
        }

        int size = scriptList == null ? 0 : scriptList.size();
        if (isAll && size <= 0) {
            Log.w(TAG, "init isAll && size <= 0，，没有可用的远程函数");
            return response;
        }


        if (isAll) {  // 必须在测试 invoke 前把配置 put 进 FUNCTION_MAP！ 如果要做成完全校验通过才更新 FUNCTION_MAP，但又不提供 忽略校验 参数，似乎无解
            FUNCTION_MAP = new LinkedHashMap<>();
        }
        Map<String, JSONObject> newMap = FUNCTION_MAP;  // 必须在测试 invoke 前把配置 put 进 FUNCTION_MAP！ new LinkedHashMap<>();

        for (int i = 0; i < size; i++) {
            JSONObject item = scriptList.getJSONObject(i);
            item = item == null ? null : item.getJSONObject(FUNCTION_);
            if (item == null) {
                continue;
            }

            JSONObject demo = JSON.parseObject(item.getString("demo"));
            if (demo == null) {
                onServerError("字段 demo 的值必须为合法且非 null 的 JSONObejct 字符串！", shutdownWhenServerError);
            }
            String name = item.getString("name");
            if (demo != null && !demo.containsKey("result()")) {
                demo.put("result()", getFunctionCall(name, item.getString("arguments")));
            }
            //			demo.put(JSONRequest.KEY_TAG, item.getString(JSONRequest.KEY_TAG));
            //			demo.put(JSONRequest.KEY_VERSION, item.getInteger(JSONRequest.KEY_VERSION));
            //加载脚本
            if (item.get("language") != null) {
                String language = item.getString("language");
                if (SCRIPT_EXECUTOR_MAP.get(language) == null) {
                    onServerError("找不到脚本语言 " + language + " 对应的执行引擎！请先依赖相关库并在后端 APIJSONFunctionParser<T> 中注册！", shutdownWhenServerError);
                }
                ScriptExecutor scriptExecutor = SCRIPT_EXECUTOR_MAP.get(language);
                scriptExecutor.load(name, scriptMap.get(name).getString("script"));
            }
            newMap.put(name, item);  // 必须在测试 invoke 前把配置 put 进 FUNCTION_MAP！

            String[] methods = StringUtil.split(item.getString("methods"));

            if (methods == null || methods.length <= 0) {
                methods = ALL_METHODS;
            }

            if (demo != null) {
                demo.put(JSONRequest.KEY_TAG, item.get(JSONRequest.KEY_TAG));
                demo.put(JSONRequest.KEY_VERSION, item.get(JSONRequest.KEY_VERSION));
            }
            for (String method : methods) {
                JSONObject r = APIJSON_CREATOR.createParser()
                        .setMethod(RequestMethod.valueOf(method))
                        .setNeedVerify(false)
                        .parseResponse(demo);

                if (!JSONResponse.isSuccess(r)) {
                    onServerError(JSONResponse.getMsg(r), shutdownWhenServerError);
                }
            }
        }
        return response;
    }

    /**
     * 获取函数调用代码
     *
     * @param name
     * @param arguments
     * @return
     */
    private static String getFunctionCall(String name, String arguments) {
        return name + "(" + StringUtil.getTrimedString(arguments) + ")";
    }

}
